/*******************************************************
*                                                     *
*  -------------------------------------------------  *
*  |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  *
*  -------------------------------------------------  *
*  |     0     |     8     |    16     |     24    |  *
*  -------------------------------------------------  *
*  |    R6     |    R7     |    R8     |    R9     |  *
*  -------------------------------------------------  *
*  -------------------------------------------------  *
*  |  8  |  9  |  10 |  11 |  12 |  13 |  14 |  15 |  *
*  -------------------------------------------------  *
*  |     32    |    40     |     48    |     56    |  *
*  -------------------------------------------------  *
*  |    R10    |    R11    |     R12   |     R13   |  *
*  -------------------------------------------------  *
*  -------------------------------------------------  *
*  |  16 |  17 |  18 |  19 |  20 |  21 |  22 |  23 |  *
*  -------------------------------------------------  *
*  |     64    |    72     |     80    |     88    |  *
*  -------------------------------------------------  *
*  |   R14/LR  |    R15    |     F1    |     F3    |  *
*  -------------------------------------------------  *
*  -------------------------------------------------  *
*  |  24 |  25 |  26 |  27 |  28 | 29  |           |  *
*  -------------------------------------------------  *
*  |     96    |    104    |    112    |    120    |  *
*  -------------------------------------------------  *
*  |    F5     |    F7     |     PC    |           |  *
*  -------------------------------------------------  *
* *****************************************************/

.file  "jump_s390x_sysv_elf_gas.S"
.text
.align  4 # According to the sample code in the ELF ABI docs
.global jump_fcontext
.type   jump_fcontext, @function

#define GR_OFFSET	0
#define LR_OFFSET	64
#define SP_OFFSET	72
#define FP_OFFSET	80
#define PC_OFFSET	112
#define L_CTX		120
#define L_STACKFRAME	120

jump_fcontext:
    
    # Reserved the space for stack to store the data of current context
    # before we jump to the new context.
    aghi %r15,-L_STACKFRAME

    # save the registers to the stack
    stmg %r6, %r15, GR_OFFSET(%r15)

    # save the floating point registers
    std  %f0,FP_OFFSET(%r15)
    std  %f3,FP_OFFSET+8(%r15)
    std  %f5,FP_OFFSET+16(%r15)
    std  %f7,FP_OFFSET+24(%r15)

    # Save LR as PC
    stg  %r14,PC_OFFSET(%r15)

    # Store the SP pointing to the old context-data into R0
    lgr	 %r0,%r15

    # Get the SP pointing to the new context-data
    # Note: Since the return type of the jump_fcontext is struct whose
    # size is more than 8. The compiler automatically passes the 
    # address of the transfer_t where the data needs to store into R2.

    # Hence the first param passed to the jump_fcontext which represent
    # the fctx we want to switch to is present in R3
    # R2 --> Address of the return transfer_t struct
    # R3 --> Context we want to switch to
    # R4 --> Data
    lgr	%r15,%r3

    # Load the registers with the data present in context-data of the
    # context we are going to switch to
    lmg	%r6, %r14, GR_OFFSET(%r15)

    # Restore Floating point registers
    ld	 %f1,FP_OFFSET(%r15)
    ld	 %f3,FP_OFFSET+8(%r15)
    ld	 %f5,FP_OFFSET+16(%r15)
    ld	 %f7,FP_OFFSET+24(%r15)

    # Load PC
    lg   %r1,PC_OFFSET(%r15)

    # Adjust the stack 
    aghi %r15,120

    # R2 --> Address where the return transfer_t is stored
    # R0 --> FCTX
    # R4 --> DATA

    # Store the elements to return transfer_t
    stg %r15, 0(%r2)
    stg %r4, 8(%r2)

    # Note: The address in R2 points to the place where the return
    # transfer_t is stored. Since context_function take transfer_t
    # as first parameter. And R2 is the register which holds the
    # first parameter value.

    #jump to context
    br  %r1

.size   jump_fcontext,.-jump_fcontext
# Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits



